import { Help } from './help.js';

// 疾病区块类，用于管理感染状态
class IllBlock {
    constructor(total = 0) {
        this.death = 0; // 死亡人数
        this.unincubation = 0; // 非潜伏期人数
        this.incubation = 0; // 潜伏期人数
        this.knowInfected = 0; // 已知感染人数
        this.total = total; // 总人数
    }

    // 获取各种状态的人数
    getDeath() { return this.death; }
    getUnincubation() { return this.unincubation; }
    getIncubation() { return this.incubation; }
    getKnowInfected() { return this.knowInfected; }
    getTotal() { return this.total; }

    // 修改各种状态的人数
    subDeath(num) { this.death = Help.sub(this.death, num); }
    addDeath(num) { this.death += num; }
    subUnincubation(num) { this.unincubation = Help.sub(this.unincubation, num); }
    addUnincubation(num) { this.unincubation += num; }
    setUnincubation(num) { this.unincubation = num; }
    subIncubation(num) { this.incubation = Help.sub(this.incubation, num); }
    addIncubation(num) { this.incubation += num; }
    setIncubation(num) { this.incubation = num; }
    subKnowInfected(num) { this.knowInfected = Help.sub(this.knowInfected, num); }
    addKnowInfected(num) { this.knowInfected += num; }
    subTotal(num) { this.total = Help.sub(this.total, num); }
    addTotal(num) { this.total += num; }

    // 按比例减少人口（饥荒等情况）
    propDecrease(famineProp) {
        const unincubationDeath = Math.floor(this.unincubation * famineProp);
        this.subUnincubation(unincubationDeath);
        const incubationDeath = Math.floor(this.incubation * famineProp);
        this.subIncubation(incubationDeath);
        this.death += unincubationDeath + incubationDeath;
        // 在健康人中减少
        this.death += Math.floor(this.getUninfected() * famineProp);
    }

    // 打印状态（调试用）
    print() {
        console.log(`death: ${this.death}`);
        console.log(`unincubation: ${this.unincubation}`);
        console.log(`incubation: ${this.incubation}`);
        console.log(`knowInfected: ${this.knowInfected}`);
        console.log(`total: ${this.total}`);
        console.log('[finished]');
    }

    // 获取感染者总数
    getInfected(isAlive = true) {
        if (isAlive) {
            return this.unincubation + this.incubation;
        } else {
            return this.death + this.unincubation + this.incubation;
        }
    }

    // 获取未感染者数量
    getUninfected() {
        return this.getAlive() - this.getInfected();
    }

    // 获取存活人数
    getAlive() {
        return this.total - this.death;
    }

    // 获取发病率
    getMorbidity() {
        const alive = this.getAlive();
        if (alive === 0) {
            return 0;
        } else {
            return this.unincubation / alive;
        }
    }

    // 获取死亡率
    getDeathRate() {
        if (this.total === 0) {
            return 0;
        } else {
            return this.death / this.total;
        }
    }

    // 添加另一个疾病区块的数据
    add(b) {
        this.unincubation += b.unincubation;
        this.incubation += b.incubation;
        this.knowInfected += b.knowInfected;
        this.total += b.total;
    }

    // 减去另一个疾病区块的数据
    sub(b) {
        this.subUnincubation(b.unincubation);
        this.subIncubation(b.incubation);
        this.subKnowInfected(b.knowInfected);
        this.subTotal(b.total);
    }

    // 生成输出区块（用于人口迁移）
    genOutputBlock(baseNum, randCoe = 0, isCheck = false) {
        const alive = this.getAlive();
        const unincubatProp = this.unincubation / alive;
        const incubatProb = this.incubation / alive;
        
        if (isCheck) {
            incubatProb *= 0.5; // 检查会拦截一半发病的
        }
        
        let outputNum = baseNum;
        if (randCoe > 0) {
            outputNum = Math.floor(Help.randJump(baseNum, randCoe));
        }

        // 创建迁出块
        const result = new IllBlock(outputNum);
        result.unincubation = Math.floor(outputNum * unincubatProp);
        result.incubation = Math.floor(outputNum * incubatProb);
        result.total = outputNum;

        // 从当前区块减去迁出的人口
        this.sub(result);
        return result;
    }
}

// 疾病类，管理疾病参数
class Ill {
    constructor(start = false) {
        this.r = 0.02; // 传染率
        this.conversion = 1.0 / 14; // 潜伏期转化率
        this.lethality = 0.05; // 致命性
        this.healing = 0.29; // 治愈率
        this.variationCoe = 0.05; // 变异比例系数
        this.start = start; // 是否已开始传染
    }

    // 打印疾病参数（调试用）
    print() {
        console.log(`infection: ${this.r}`);
        console.log(`conversion: ${this.conversion}`);
        console.log(`lethality: ${this.lethality}`);
        console.log(`healing: ${this.healing}`);
        console.log('[finished]');
    }

    // 获取治愈率
    getHealing() { return this.healing; }
    // 获取传染率
    getR() { return this.r; }

    // 疾病变异
    variation() {
        this.r = Help.randJump(this.r, this.variationCoe);
        this.conversion = Help.randJump(this.conversion, this.variationCoe);
        this.lethality = Help.randJump(this.lethality, this.variationCoe);
        this.healing = Help.randJump(this.healing, this.variationCoe);
    }

    // 融合两个疾病参数
    fuse(i) {
        if (!this.start) {
            this.start = true;
            this.r = i.r;
            this.conversion = i.conversion;
            this.lethality = i.lethality;
            this.healing = i.healing;
        } else {
            this.r = (this.r + i.r) / 2;
            this.conversion = (this.conversion + i.conversion) / 2;
            this.lethality = (this.lethality + i.lethality) / 2;
            this.healing = (this.healing + i.healing) / 2;
        }
    }

    // 获取比例数量（辅助函数）
    getPropNum(baseNum, prop, jumpRange = 0.1) {
        let newNum = Math.floor(baseNum * prop);
        // 添加随机波动
        if (jumpRange > 0) {
            newNum = Math.floor(Help.randJump(newNum, jumpRange));
        }
        if (newNum > baseNum) {
            newNum = baseNum;
        }
        return newNum;
    }

    // 更新感染情况
    updateInfected(b, avgContactNum, tempR = -1) {
        if (tempR === -1) {
            tempR = this.r;
        }

        const uninfected = b.getUninfected();
        const unitInfection = tempR * avgContactNum;
        let newIncubation = Math.floor(b.getInfected() * unitInfection);
        
        // 添加随机波动
        newIncubation = Math.floor(Help.randJump(newIncubation, 0.1));
        
        if (newIncubation > uninfected) {
            newIncubation = uninfected;
        }
        b.addIncubation(newIncubation);
    }

    // 更新潜伏期
    updateIncubation(b) {
        const newIncubation = this.getPropNum(b.getIncubation(), this.conversion);
        b.subIncubation(newIncubation);
        b.addUnincubation(newIncubation); // 潜伏期结束转为非潜伏期（有症状）
    }

    // 更新治愈情况
    updateHealing(b, tempHealing = -1, lifeBlock = null) {
        if (tempHealing === -1) {
            tempHealing = this.healing;
        }

        const incubationHeal = this.getPropNum(b.getIncubation(), tempHealing);
        b.subIncubation(incubationHeal);
        const unincubationHeal = this.getPropNum(b.getUnincubation(), tempHealing);
        b.subUnincubation(unincubationHeal);
        const healingNum = incubationHeal + unincubationHeal;

        if (lifeBlock !== null) { // 出院
            b.subTotal(healingNum);
            b.subKnowInfected(healingNum);
            lifeBlock.addTotal(healingNum);
        }
    }

    // 更新死亡情况
    updateDeath(b) {
        // 潜伏期不死
        const unincubationDeath = this.getPropNum(b.getUnincubation(), this.lethality);
        b.subUnincubation(unincubationDeath);
        b.addDeath(unincubationDeath);
    }

    // 是否已开始传染
    isStart() { return this.start; }
}

export { IllBlock, Ill };
